package org.gbif.agi.webapp.action;

import java.util.HashSet;
import java.util.LinkedList;
import java.util.List;
import java.util.Set;

import org.appfuse.webapp.action.BaseAction;
import org.gbif.agi.model.Genus;
import org.gbif.agi.model.GenusRelationship;
import org.gbif.agi.service.GenusManager;
import org.gbif.agi.webapp.action.model.GenusName;
import org.gbif.agi.webapp.action.model.GroupedGenera;
import org.gbif.agi.webapp.action.model.GroupedGenusRelationships;

import com.opensymphony.xwork2.Preparable;

public class GenusAction extends BaseAction implements Preparable {
    private GenusManager genusManager;
    private List genuss;
    private Genus genus;
    private Long  id;
    private String genusName;
    private List<String> genusNameSuggest = new LinkedList<String>();
    private List<GroupedGenera> groupedGeneraList = new LinkedList<GroupedGenera>();
    private GroupedGenusRelationships groupedGenusRelationships = new GroupedGenusRelationships();
    
    public void setGenusManager(GenusManager genusManager) {
        this.genusManager = genusManager;
    }

    public List getGenuss() {
        return genuss;
    }

    /**
     * Grab the entity from the database before populating with request parameters
     */
    public void prepare() {
        if (getRequest().getMethod().equalsIgnoreCase("post")) {
            // prevent failures on new
            String genusId = getRequest().getParameter("genus.id");
            if (genusId != null && !genusId.equals("")) {
                genus = genusManager.get(new Long(genusId));
            }
        }
    }

    public String list() {
        genuss = genusManager.getAll();
        return SUCCESS;
    }

    public void setId(Long  id) {
        this. id =  id;
    }

    public Genus getGenus() {
        return genus;
    }

    public void setGenus(Genus genus) {
        this.genus = genus;
    }

    public String delete() {
        genusManager.remove(genus.getId());
        saveMessage(getText("genus.deleted"));

        return SUCCESS;
    }

    public String edit() {
        if (id != null) {
            genus = genusManager.get(id);
        } else {
            genus = new Genus();
        }

        return SUCCESS;
    }

    public String detail() {
        String genusId = getRequest().getParameter("id");
        if (genusId != null && !genusId.equals("")) {
        	genus = genusManager.getDetailed(id);            	
        }
        
        if (genus==null) {
        	return CANCEL;
        } else {
	        // build an object that groups the relationships for easy rendering
	        groupRelationships(groupedGenusRelationships, genus.getFromRelationships());
	        groupRelationships(groupedGenusRelationships, genus.getToRelationships());
        	return SUCCESS;
        }
    }

	/**
	 * Groups the relationships by type
	 */
	private void groupRelationships(GroupedGenusRelationships ggr, List<GenusRelationship> genusRelationships) {
		for (GenusRelationship gr : genusRelationships) {
        	List<GenusRelationship> relationships = ggr.getRelationships().get(gr.getRelationshipType());
        	if (relationships == null) {
        		relationships = new LinkedList<GenusRelationship>();
        		ggr.getRelationships().put(gr.getRelationshipType(), relationships);
        	}
        	relationships.add(gr);
        }
	}

    public String save() throws Exception {
        if (cancel != null) {
            return "cancel";
        }

        if (delete != null) {
            return delete();
        }

        boolean isNew = (genus.getId() == null);

        genusManager.save(genus);

        String key = (isNew) ? "genus.added" : "genus.updated";
        saveMessage(getText(key));

        if (!isNew) {
            return INPUT;
        } else {
            return SUCCESS;
        }
    }

	public String getGenusName() {
		return genusName;
	}

	public void setGenusName(String genusName) {
		this.genusName = genusName;
	}
    
	public String autocompleteGenus() {
		log.info("genusName: " + genusName);
		List<Genus> suggestions = genusManager.getSuggestions(genusName);
		for (Genus g : suggestions) {
			genusNameSuggest.add(g.getFullScientificName());
		}
    	return SUCCESS;
    }

    
	public String search() {
		log.info("genusName: " + genusName);
		
		// this is somewhat horrible and needing tidied!
		List<Genus> genera = genusManager.getDetailed(genusName);
		Set<Long> processedIds = new HashSet<Long>();
		
		for (Genus g : genera) {
			// it is not already processed
			if (!processedIds.contains(g.getId())) {
				GroupedGenera gg = new GroupedGenera();
				groupedGeneraList.add(gg);
				gg.getGenera().add(g);				
				processedIds.add(g.getId());
				
				// find the relationships that are homonyms
				for (GenusRelationship gr : g.getToRelationships()) {
					// errrr.... hardcoded? ummmm
					if (gr.getRelationshipType().getId() == 1
							&& gr.getDeleted() == null) {
						if (!processedIds.contains(gr.getFromGenus().getId())) {
							gg.getGenera().add(gr.getFromGenus());
							processedIds.add(gr.getFromGenus().getId());
						}
					}
				}
				for (GenusRelationship gr : g.getFromRelationships()) {
					// errrr.... hardcoded? ummmm
					if (gr.getRelationshipType().getId() == 1
							&& gr.getDeleted() == null) {
						if (!processedIds.contains(gr.getToGenus().getId())) {
							gg.getGenera().add(gr.getToGenus());
							processedIds.add(gr.getToGenus().getId());
						}
					}
				}
			}
		}
		
		log.info("size: " + groupedGeneraList.size());
    	return SUCCESS;
    }

	public List<String> getGenusNameSuggest() {
		return genusNameSuggest;
	}

	public void setGenusNameSuggest(List<String> genusNameSuggest) {
		this.genusNameSuggest = genusNameSuggest;
	}

	public List<GroupedGenera> getGroupedGeneraList() {
		return groupedGeneraList;
	}

	public void setGroupedGeneraList(List<GroupedGenera> groupedGeneraList) {
		this.groupedGeneraList = groupedGeneraList;
	}

	public GroupedGenusRelationships getGroupedGenusRelationships() {
		return groupedGenusRelationships;
	}
}